use core::fmt::{Display, Formatter};

use crate::addrspace::PhysAddr;

use super::{Memblock, MemblockType};

fn memblock_dump(
    ty: &MemblockType,
    f: &mut Formatter<'_>,
    width: usize,
) -> Result<(), core::fmt::Error> {
    writeln!(f, " {}.cnt  = {:#x}", ty.name, ty.cnt)?;

    for i in 0..ty.cnt {
        let rgn = &ty.regions[i];
        let base = rgn.base;
        let size = rgn.size;
        let end = PhysAddr::from((base + size).value().wrapping_sub(1));
        let flags = rgn.flags;
        writeln!(
            f,
            " {}[{:#x}]\t[{:#0width$x}-{:#0width$x}], {:#0width$x} bytes flags: {:#x}",
            ty.name,
            i,
            base.value(),
            end.value(),
            size,
            flags
        )?;
    }
    Ok(())
}

impl Display for Memblock {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
        let width = core::mem::size_of::<usize>() * 2 + 2;
        writeln!(f, "MEMBLOCK configuration:")?;
        writeln!(
            f,
            " memory size = {:#0width$x} reserved size = {:#0width$x}",
            self.memory.total_size, self.reserved.total_size
        )?;

        memblock_dump(&self.memory, f, width)?;
        memblock_dump(&self.reserved, f, width)
    }
}
